#include "StdAfx.h"
#include "LinguisticProcessing.h"
#include <cmath>

//Create the linguistic processing
CLinguisticProcessing::CLinguisticProcessing(string corpuspath)
{
	//Load the file
	try
	{
		corpus = bf.SetCorpus(corpuspath);
	}
	catch(string exceptionmessage)
	{
		throw exceptionmessage;
	}
	logspace = 0;
}

//Create the linguistic processing
CLinguisticProcessing::CLinguisticProcessing(string corpuspath, unsigned int numberofbins)
{
	//load the file
	try
	{
		corpus = bf.SetCorpus(corpuspath);
	}
	catch(string exceptionmessage)
	{
		throw exceptionmessage;
	}
	
	//sort the corpus
	CLinguisticProcessing::SortCorpus();

	//calcualte the number of words in each bin
	double maxlog = log10((double)corpus.size());
	vector<double> lognumber;
	lognumber.resize(numberofbins);
	for(unsigned int i=0; i<(unsigned int)lognumber.size(); i++)
		lognumber[i] = maxlog/(double)(numberofbins)*(double)(i+1);

	//label the corpus by the bins
	unsigned int currentbin = 0;

	wordsinbin.resize(numberofbins);
	for(unsigned int i=0; i<(unsigned int)wordsinbin.size(); i++)
		wordsinbin[i] =0 ;

	for(unsigned int i=0; i<(unsigned int)corpus.size(); i++)
	{
		double originalnumber = pow((double)10.0, lognumber[currentbin]);
		unsigned int originalfrequency;
		if(originalnumber-(double)((unsigned int)(originalnumber))>=0.5)
			originalfrequency = (unsigned int)originalnumber+1;
		else
			originalfrequency = (unsigned int)originalnumber;
		corpus[i].bin = currentbin;
		wordsinbin[currentbin] ++;

		//increase the current bin
		if(i>originalfrequency)
			currentbin ++;

		if(currentbin>=numberofbins)
			throw string("errors in locating bins!");
	}

	logspace = 1;

}

//Get the linguistic features
vector<double> CLinguisticProcessing::GetLinguisticFeature(string document)
{
	if(corpus.size()==0)
		throw string("No corpus is set");

	//Count keyword frequency
	//vector<unsigned int> keywordfrequency = CLinguisticProcessing::CountFrequency(document);
	////Create the feature
	//vector<double> linguisticfeatures;
	//linguisticfeatures.resize(corpus.size());
	////Get the features
	//for(unsigned int i=0; i<(unsigned int)linguisticfeatures.size(); i++)
	//	linguisticfeatures[i] = (double)keywordfrequency[i];
	//find the cooccurrence of the corpus word
	vector<double> linguisticfeatures;
	linguisticfeatures.resize(corpus.size());
	for(unsigned int i=0; i<(unsigned int)corpus.size(); i++)
	{
		string searchword = " " + (corpus[i].word + " ");
		if(document.find(searchword)!=string::npos)
			linguisticfeatures[i] = 1.0;
		else
			linguisticfeatures[i] = 0.0;
	}
	if(logspace==0)
	{
		return linguisticfeatures;
	}
	else
	{
		//create the logspace feature
		vector<double> logspacefeatures;
		logspacefeatures.resize(wordsinbin.size());
		for(unsigned int i=0; i<(unsigned int)logspacefeatures.size(); i++)
			logspacefeatures[i] = 0.0;

		for(unsigned int i=0; i<(unsigned int)linguisticfeatures.size(); i++)
		{
			if(linguisticfeatures[i]!=0)
				logspacefeatures[corpus[i].bin] += 1.0;
		}
		for(unsigned int i=0; i<(unsigned int)logspacefeatures.size(); i++)
		{
			if(wordsinbin[i]!=0)
				logspacefeatures[i] = logspacefeatures[i]/(double)wordsinbin[i];
			else
				logspacefeatures[i] = (double)0.0;
		}
		return logspacefeatures;
	}
}

//Get the keywords in the document as set by the corpus
vector<string> CLinguisticProcessing::GetKeywords(string document)
{
	vector<string> keywords;
	if(corpus.size()==0)
		throw string("No corpus is set");
	//Search if keyword in the corpus is presented in the document or not
	for(unsigned int i=0; i<(unsigned int)corpus.size(); i++)
	{
		if(document.find(corpus[i].word)!=string::npos)
			keywords.push_back(corpus[i].word);
	}
	return keywords;
}

CLinguisticProcessing::~CLinguisticProcessing(void)
{
}

//Save the corpus into a file
void CLinguisticProcessing::SaveCorpusToFile(string filepath)
{
	if(corpus.size()==0)
		throw string("Corpus is empty");
	//Save the corpus to the filepath
	std::ofstream outstring(filepath.c_str());
	for(unsigned int i=0; i<(unsigned int)corpus.size()-1; i++)
	{
		outstring << corpus[i].word.c_str() << '\t' << corpus[i].frequency << "\r\n";
	}
	outstring << corpus[corpus.size()-1].word.c_str() << '\t' << corpus[corpus.size()-1].frequency;
	outstring.close();
	return;
}

//Count the frequencies of keywords in a document
vector<unsigned int> CLinguisticProcessing::CountFrequency(string document)
{
	if(corpus.size()==0)
		throw string("Corpus is empty");
	//create the frequency
	vector<unsigned int> frequency;
	frequency.resize(corpus.size());
	//iterate the keywords and counte their frequency in the document
	for(unsigned int i=0; i<(unsigned int)corpus.size(); i++)
	{
		frequency[i] = 0;
		string::size_type foundposition = 0;
		string searchword = " " + (corpus[i].word + " ");
		while(foundposition!=string::npos)
		{
			foundposition = document.find(searchword, foundposition);
			if(foundposition==string::npos)
				continue;
			foundposition ++;
			frequency[i] ++;
		}
	}
	return frequency;
}

//Find the most frequency keywords in a document
string CLinguisticProcessing::FindFrequentKeywords(string document, unsigned int numberofwords)
{
	//Count the frequency
	vector<unsigned int> frequency;
	try
	{
		frequency = CLinguisticProcessing::CountFrequency(document);
	}
	catch(string exceptionmessage)
	{
		throw exceptionmessage;
	}

	//Sort the frequency
	string keywords;
	vector<unsigned int> sequence;
	for(unsigned int i=0; i<corpus.size(); i++)
		sequence.push_back(i);
	for(unsigned int i=0; i<corpus.size(); i++)
	{
		for(unsigned int j=i+1; j<corpus.size(); j++)
		{
			if(frequency[i]<frequency[j])
			{
				//switch the frequency
				unsigned int frequencytemp = frequency[j];
				frequency[j] = frequency[i];
				frequency[i] = frequencytemp;
				//switch the sequence
				unsigned int sequencetemp = sequence[j];
				sequence[j] = sequence[i];
				sequence[i] = sequencetemp;
			}
		}
	}

	//get the most frequent keywords
	for(unsigned int i=0; i<numberofwords; i++)
	{
		if(frequency[i]>0)
		{
			keywords += corpus[sequence[i]].word;
			keywords += "\r\n";
		}
	}

	return keywords;
}

//sort the corpus
void CLinguisticProcessing::SortCorpus()
{
	//if the corpus is zero
	if(corpus.size()==0)
		throw string("corpus is not set!");

	//sort the corpus
	for(unsigned int i=0; i<(unsigned int)corpus.size(); i++)
	{
		for(unsigned int j=i; j<(unsigned int)corpus.size(); j++)
		{
			if(corpus[i].frequency<corpus[j].frequency)
			{
				_corpusunit tempcorpusunit = corpus[i];
				corpus[i] = corpus[j];
				corpus[j] = tempcorpusunit;
			}
		}
	}
	return;
}
